<template>
    <div class="wrap normal">
        <!-- 搜索条件 -->
        <div class="wrap-form">
            <el-row>
                <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
                    <div class="left-panel">
                        <el-button type="primary" icon="el-icon-sort" @click="pageOperate('toggle')">展开/折叠</el-button>
                        <el-button type="primary" icon="el-icon-plus" v-hasPerm="'system:menuManage:add'" @click="pageOperate('add')">添加</el-button>
                        <el-button icon="el-icon-refresh" @click="pageOperate('refresh')">刷新</el-button>
                    </div>
                </el-col>
            </el-row>
        </div>
        <!-- table数据 -->
        <div class="wrap-table">
            <el-table ref="menuTable" :data="tableData" border row-key="id" :default-expand-all="isExpand" v-loading="tableLoading" :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" :header-cell-style="{ background: '#F5F6FA' }" @sort-change="tableSortChange">
                <el-table-column prop="name" label="菜单名称" min-width="140" show-overflow-tooltip> </el-table-column>
                <el-table-column prop="path" label="路由地址" min-width="160" show-overflow-tooltip> </el-table-column>
                <el-table-column prop="perms" label="权限标识" min-width="100" show-overflow-tooltip> </el-table-column>
                <el-table-column prop="urlPerm" label="接口配置" min-width="160" show-overflow-tooltip> </el-table-column>
                <el-table-column prop="type" label="类型" min-width="80">
                    <template slot-scope="scope">
                        {{ scope.row.type | filterMenuType }}
                    </template>
                </el-table-column>
                <el-table-column label="状态" min-width="80">
                    <template slot-scope="scope">
                        <el-tag :type="$options.filters.filterStatusClass(scope.row.status)">{{ scope.row.status | filterStatus }}</el-tag>
                    </template>
                </el-table-column>
                <el-table-column label="图标" min-width="80" align="center">
                    <template slot-scope="scope">
                        <i class="iconfont" :class="scope.row.icon" v-if="scope.row.icon"></i>
                        <span v-else>-</span>
                    </template>
                </el-table-column>
                <el-table-column prop="sort" label="排序" min-width="80" align="center" sortable="custom"> </el-table-column>
                <el-table-column label="操作" width="100" fixed="right">
                    <template slot-scope="scope">
                        <el-button type="text" v-hasPerm="'system:menuManage:edit'" @click="pageOperate('edit', scope.row)">修改</el-button>
                        <el-button type="text" v-hasPerm="'system:menuManage:delete'" @click="pageOperate('deleteOne', scope.row)">删除</el-button>
                    </template>
                </el-table-column>
            </el-table>
        </div>
        <!-- 路由更新表单 -->
        <el-dialog v-if="operateDialog" :title="operateTitle" :visible.sync="operateDialog" :width="`${operateWidth}px`" @close="closeOperateDialog" :close-on-press-escape="false" :close-on-click-modal="false" append-to-body>
            <el-form ref="operateForm" :model="operateForm" :rules="operateRules" label-width="100px">
                <el-form-item label="菜单类型" prop="type">
                    <el-radio-group v-model="operateForm.type" @change="menuTypeChange">
                        <el-radio v-for="item in menuTypeOptions" :key="item.value" :label="item.value">{{ item.label }}</el-radio>
                    </el-radio-group>
                </el-form-item>
                <el-form-item label="父级菜单" prop="parentId" v-if="operateForm.type !== 0">
                    <el-cascader v-model="operateForm.parentId" :options="menuOptions" :props="{ label: 'name', value: 'id', checkStrictly: true }" clearable placeholder="请选择父级菜单" style="width: 100%"></el-cascader>
                </el-form-item>
                <el-form-item label="菜单名称" prop="name">
                    <el-input v-model="operateForm.name" clearable placeholder="请输入菜单名称"></el-input>
                </el-form-item>
                <el-form-item label="路由地址" prop="path" v-if="operateForm.type !== 2">
                    <el-input v-model="operateForm.path" clearable placeholder="请输入路由地址"></el-input>
                </el-form-item>
                <el-form-item label="权限标识" prop="perms" v-if="operateForm.type === 2">
                    <el-input v-model="operateForm.perms" clearable placeholder="请输入权限标识"></el-input>
                </el-form-item>
                <el-form-item label="接口配置" v-if="operateForm.type === 1 || operateForm.type === 2">
                    <el-input class="input-with-select" v-model="operateForm.apiUrl" placeholder="请输入接口地址" clearable>
                        <el-select v-model="operateForm.apiMethod" slot="prepend" placeholder="请选择" clearable style="width: 120px">
                            <el-option v-for="(item, index) in restfulApiOptions" :key="index" :label="item.label" :value="item.value"></el-option>
                        </el-select>
                    </el-input>
                </el-form-item>
                <el-form-item label="菜单图标" prop="icon" v-if="operateForm.type !== 2">
                    <el-popover width="300" trigger="click" placement="right">
                        <ul class="icon-ul">
                            <li class="icon-li" v-for="item in iconOptions.glyphs" :key="item.font_class" @click="selectIcon(item.font_class)">
                                <i class="iconfont" :class="`admin-icon-${item.font_class}`"></i>
                            </li>
                        </ul>
                        <el-input slot="reference" v-model="operateForm.icon" placeholder="请选择菜单图标" clearable></el-input>
                    </el-popover>
                </el-form-item>
                <el-form-item label="状态" prop="status">
                    <el-radio-group v-model="operateForm.status">
                        <el-radio v-for="(item, index) in statusOptions" :label="item.value" :key="index">{{ item.label }}</el-radio>
                    </el-radio-group>
                </el-form-item>
                <el-form-item label="排序" prop="sort">
                    <el-input-number v-model="operateForm.sort" size="small" :min="0" />
                </el-form-item>
            </el-form>
            <div slot="footer" class="dialog-footer">
                <el-button @click="closeOperateDialog">取 消</el-button>
                <el-button type="primary" :loading="operateLoading" @click="operateSubmit">确 定</el-button>
            </div>
        </el-dialog>
    </div>
</template>

<script>
import { treeToArray } from '@/utils'
import iconOptions from '@/iconfont/iconfont.json'
import { menuTypeOptions, statusOptions, restfulApiOptions } from '@/filters/options'
import { getMenuList, addOrUpdateMenu, deleteMenu } from '@/api/system'
export default {
    name: "MenuManage",
    computed: {
        urlPerm() {
            if (this.operateForm.apiMethod && this.operateForm.apiUrl) {
                return this.operateForm.apiMethod + ':' + this.operateForm.apiUrl
            } else {
                return ''
            }
        }
    },
    data() {
        return {
            // 搜索条件
            form: {
                fieldSort: '',
                orderSort: ''
            },
            // 是否全部展开
            isExpand: false,
            // table加载状态
            tableLoading: false,
            // table数据
            tableData: [],
            // 操作
            operateType: '',
            operateTitle: '',
            operateWidth: 550,
            operateDialog: false,
            operateLoading: false,
            // 操作form
            operateForm: {
                // 主键id
                id: '',
                //类型：0目录 1菜单 2按钮
                type: 0,
                // 父id
                parentId: [],
                // 路由中文名
                name: '',
                // 路由地址
                path: '',
                // 权限标识
                perms: '',
                // 接口方法
                apiMethod: '',
                // 接口地址
                apiUrl: '',
                // 接口配置 apiMethod + ":" + apiUrl
                urlPerm: '',
                // 状态
                status: 0,
                // 图标
                icon: '',
                // 排序
                sort: 1
            },
            // 操作表单校验
            operateRules: {
                type: [
                    { required: true, message: '请选择菜单类型', trigger: ['blur', 'change'] }
                ],
                parentId: [
                    { required: true, message: '请选择父级菜单', trigger: ['blur', 'change'] }
                ],
                name: [
                    { required: true, message: '请输入菜单名称', trigger: ['blur'] }
                ],
                path: [
                    { required: true, message: '请输入路由地址', trigger: ['blur'] }
                ],
                // icon: [
                //     { required: true, message: '请选择路由图标', trigger: ['blur', 'change'] }
                // ],
                perms: [
                    { required: true, message: '请输入权限标识', trigger: ['blur'] }
                ],
                // urlPerm: [
                //     { required: true, message: '请输入接口配置', trigger: ['blur'] }
                // ],
                status: [
                    { required: true, message: '请选择状态', trigger: ['blur', 'change'] }
                ],
                sort: [
                    { required: true, message: '请输入排序顺序', trigger: ['blur'] }
                ],
            },
            // 菜单类型
            menuTypeOptions,
            // 菜单选项
            menuOptions: [],
            // 图标选项
            iconOptions,
            // 接口
            restfulApiOptions,
            // 状态选项
            statusOptions
        }
    },
    methods: {
        // 排序
        tableSortChange(data) {
            this.form.fieldSort = data.prop
            this.form.orderSort = data.order
            this.getTableData()
        },
        // 选择icon
        selectIcon(font_class) {
            this.operateForm.icon = `admin-icon-${font_class}`
        },
        // 菜单类型修改
        menuTypeChange() {
            this.$nextTick(() => {
                this.$refs.operateForm.clearValidate()
            })
        },
        // 数据
        getTableData() {
            this.tableLoading = true
            getMenuList({
                ...this.form
            }).then(res => {
                this.tableData = res.data
                this.tableLoading = false
                this.menuOptions = this.addDisbled(res.data)
            }).catch(error => {
                this.tableLoading = false
            })
        },
        // 获取父级id组成的数组
        getParentIdList(menus, id) {
            let idList = []
            let obj = menus.filter(item => item.id === id)[0]
            idList.push(obj.id)
            if (obj.parentId !== '0') {
                let fIdList = this.getParentIdList(menus, obj.parentId)
                idList = fIdList.concat(idList)
            }
            return idList
        },
        // 添加禁用key
        addDisbled(list) {
            list.forEach(item => {
                item['disabled'] = false
                if (item.children && item.children.length) this.addDisbled(item.children)
            })
            return list
        },
        // 处理禁用项
        calcDisData(routes, id) {
            routes.forEach((item) => {
                if (item.id === id) {
                    item.disabled = true
                } else {
                    item.disabled = false
                }
                if (item.children && item.children.length) {
                    this.calcDisData(item.children, id)
                }
            })
        },
        // 操作
        async pageOperate(type, row) {
            this.operateType = type
            switch (type) {
                case 'toggle':
                    this.isExpand = !this.isExpand
                    this.tableData.forEach((item, index) => {
                        this.$refs.menuTable.toggleRowExpansion(item, this.isExpand)
                    })
                    break;
                case 'refresh':
                    Object.assign(this.$data, this.$options.data())
                    this.getTableData()
                    break;
                case 'add':
                    this.operateDialog = true
                    this.operateTitle = '新增菜单'
                    break;
                case 'edit':
                    this.operateDialog = true
                    this.operateTitle = '修改菜单'
                    let editData = JSON.parse(JSON.stringify(row))
                    let id = editData.id
                    // 处理禁用当前项
                    this.calcDisData(this.menuOptions, id)
                    // 转平级数组
                    let menus = treeToArray(this.menuOptions)
                    // 计算父级idList
                    let parentIdList = this.getParentIdList(menus, id)
                    // 删除最后一位
                    parentIdList.pop()
                    for (let key in this.operateForm) {
                        if (key === 'parentId') {
                            this.operateForm[key] = parentIdList
                        } else if (key === 'urlPerm' && editData.type !== 0) {
                            let urlPermList = editData['urlPerm'] ? editData['urlPerm'].split(':') : []
                            this.operateForm.apiMethod = urlPermList[0]
                            this.operateForm.apiUrl = urlPermList[1]
                        } else {
                            this.operateForm[key] = editData[key]
                        }
                    }
                    break;
                case 'deleteOne':
                    this.$confirm('确认删除此菜单?', '提示', {
                        confirmButtonText: '确定',
                        cancelButtonText: '取消',
                        type: 'warning'
                    }).then(() => {
                        deleteMenu({ id: row.id }).then(res => {
                            this.getTableData()
                            this.$message_tip(`删除成功`, 'success')
                        }).catch(error => { })
                    }).catch(() => { });
                    break;
                default:
                    break;
            }
        },
        // 关闭操作按钮
        closeOperateDialog() {
            this.operateLoading = false
            this.operateDialog = false
            this.operateType = ''
            this.operateTitle = ''
            this.operateForm = this.$options.data().operateForm
        },
        // 提交
        operateSubmit() {
            this.$refs.operateForm.validate(valid => {
                if (valid) {
                    let menuData = JSON.parse(JSON.stringify(this.operateForm))
                    if (menuData.type === 0) {
                        menuData.parentId = '0'
                    } else {
                        menuData.parentId = menuData.parentId[menuData.parentId.length - 1]
                    }
                    delete menuData.apiMethod
                    delete menuData.apiUrl
                    if (this.operateType === 'add' || this.operateType === 'edit') {
                        this.operateLoading = true
                        addOrUpdateMenu(menuData).then(res => {
                            this.getTableData()
                            this.$message_tip(`${this.operateTitle}成功`, 'success')
                            this.closeOperateDialog()
                        }).catch(error => {
                            this.operateLoading = false
                        })
                    }
                }
            })
        }
    },
    mounted() {
        this.getTableData()
    },
    watch: {
        'urlPerm': function (newVal, oldVal) {
            this.operateForm.urlPerm = newVal
        }
    }
};
</script>

<style lang="scss" scoped>
::v-deep {
    .input-with-select .el-input-group__prepend {
        color: #606266;
        background-color: #ffffff !important;
    }
}

.icon-ul {
    display: flex;
    flex-wrap: wrap;
    height: 280px;
    overflow: scroll;
    .icon-li {
        margin: 6px;
        padding: 5px 10px;
        border: 1px solid #dcdfe6;
        border-radius: 4px;
        display: flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
        transition: all 0.2s linear;
        &:hover {
            box-shadow: 0 8px 24px rgb(0 0 0 / 8%);
            transform: translate3d(0, -1px, 0);
        }
        .iconfont {
            font-size: 20px;
        }
    }
}
</style>
